package com.yayako.security.config;

import com.yayako.modules.user.service.UserService;
import com.yayako.security.authentication.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import javax.sql.DataSource;

/** @author cyy */
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired UserService userService;
  @Autowired DataSource dataSource;
  @Autowired AuthSuccessHandler authSuccessHandler;
  @Autowired AuthFailureHandler authFailureHandler;
  @Autowired MyLogoutSuccessHandler logoutSuccessHandler;
  @Autowired AuthenticationEntryPoint authenticationEntryPoint;
  @Autowired AuthAccessDeniedHandler accessDeniedHandler;

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userService).passwordEncoder(new BCryptPasswordEncoder());
    auth.userDetailsService(userDetailsService()).passwordEncoder(new BCryptPasswordEncoder());
    //        auth.jdbcAuthentication().passwordEncoder(passwordEncoder()).dataSource(dataSource);
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter = new JwtAuthenticationTokenFilter();
    http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);

    http.cors()
        .and()
        .authorizeRequests()
        .antMatchers("/**", "/mylogin", "/**/register")
        .permitAll()
        //                      .antMatchers("/admin/**", "/staff/**")
        //                      .hasRole("ADMIN")
        //                    .antMatchers("/test/**").hasRole("TEST")
        .anyRequest()
        .authenticated()
        .and()
        .formLogin() // 自定义配置表单登录
        .loginProcessingUrl("/mylogin")
        .usernameParameter("username")
        .passwordParameter("password")
        .successHandler(authSuccessHandler) // 登陆成功处理
        .failureHandler(authFailureHandler) // 登录失败处理
        .permitAll() // 允许所有用户访问登录页面
        .and()
        .logout()
        .logoutUrl("/mylogout")
        .logoutSuccessHandler(logoutSuccessHandler) // 注销失败处理
        //                    .invalidateHttpSession(true)
        .permitAll()
        .and()
        .rememberMe()
        .rememberMeParameter("rememberMe")
        .userDetailsService(userService)
        .tokenRepository(persistentTokenRepository()) // 修改token存储方式（默认存储至内存，服务器重启后即丢失）
        .tokenValiditySeconds(60 * 60 * 24); // 设置token有效时间

    http.csrf().disable();

    // 未登录
    http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);

    // 权限不足
    http.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
  }

  private CorsConfiguration buildConfig() {
    CorsConfiguration corsConfiguration = new CorsConfiguration();
    corsConfiguration.addAllowedOrigin("*");
    corsConfiguration.addAllowedHeader("*");
    corsConfiguration.addAllowedMethod("*");
    corsConfiguration.setAllowCredentials(true);
    return corsConfiguration;
  }

  @Bean
  public CorsFilter corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", buildConfig());
    return new CorsFilter(source);
  }

  @Override
  @Bean
  public UserDetailsService userDetailsService() {
    return new UserService();
  }

  /**
   * 密码编码器 密码比较机制
   *
   * @return
   */
  @Bean
  BCryptPasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
  }

  @Bean
  public PersistentTokenRepository persistentTokenRepository() {
    JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
    tokenRepository.setDataSource(dataSource);
    //		tokenRepository.setCreateTableOnStartup(true);  //  创建token记录表，创建以后即可注释掉
    return tokenRepository;
  }

  @Autowired
  public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.jdbcAuthentication().passwordEncoder(passwordEncoder()).dataSource(dataSource);
  }
}
